#!/usr/bin/env python3
# Copyright 2021 The Emscripten Authors.  All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License.  Both these licenses can be
# found in the LICENSE file.

"""Convert src/settings.js into ReSt docs that get published as
part of the emscripten docs.

This parser for src/settings.js is somewhat fragile, and
comments need to be written in a ReSt friendly way.  This
means, for example, using double backticks for keywords and
leaving a blank line before and after list blocks.

The parser does understand several "tags" which we use
settings.js.  For example [compile] and [link].
"""

import os
import sys
import subprocess

script_dir = os.path.dirname(os.path.abspath(__file__))
root_dir = os.path.dirname(os.path.dirname(script_dir))

sys.path.insert(0, root_dir)

from tools.utils import path_from_root, read_file, safe_ensure_dirs

header = '''\
.. _settings-reference:

============================
Emscripten Compiler Settings
============================

The following is a complete list of settings that can be passed
to emscripten via ``-s`` on the command line.  For example
``-sASSERTIONS`` or ``-sASSERTIONS=0``.  For more details see the
:ref:`emcc <emcc-s-option-value>` documentation.

Unless otherwise noted these settings only apply when linking
and have no effect during compilation.

.. Auto-generated by update_settings_docs.py. **DO NOT EDIT**
'''

all_tags = {
  'link': '',
  'compile+link': 'Applicable during both linking and compilation',
  'compile': 'Only applicable during compilation',
  'experimental': 'This is an experimental setting',
  'deprecated': 'This setting is deprecated',
}

output_file = path_from_root('site/source/docs/tools_reference/settings_reference.rst')


def write_setting(f, setting_name, setting_default, comment, tags):
  # Convert markdown backticks to rst double backticks
  f.write('\n.. _' + setting_name.lower() + ':\n')
  f.write('\n' + setting_name + '\n')
  f.write('=' * len(setting_name) + '\n\n')
  f.write(comment + '\n')
  for tag in tags:
    for t in tag.split():
      if all_tags[t]:
        f.write('\n.. note:: ' + all_tags[t] + '\n')
  # TODO: Properly handle multi-line values, like for INCOMING_MODULE_JS_API,
  #       which is [, newline, and then lines of content. For now print a
  #       placeholder.
  if setting_default == '[':
    setting_default = '(multi-line value, see settings.js)'
  f.write('\nDefault value: ' + setting_default + '\n')


def write_file(f):
  f.write(header)

  current_comment = []
  current_tags = []
  for line in read_file(path_from_root('src/settings.js')).splitlines():
    if 'Internal, used for testing only, from here' in line:
      break
    if not line:
      current_comment = []
      current_tags = []
    if line.startswith('//'):
      line = line[2:]
      # Strip at most one leading space
      if line and line[0] == ' ':
        line = line[1:]
      if line.startswith('[') and line.endswith(']'):
        tag = line.strip('[')
        tag = tag.rstrip(']')
        if tag in all_tags:
          current_tags.append(tag)
          continue
      current_comment.append(line)
    elif line.startswith('var'):
      # Format:
      #   var NAME = DEFAULT;
      # Split it and strip the final ';'.
      _, setting_name, _, setting_default = line.strip(';').split()
      comment = '\n'.join(current_comment).strip()
      write_setting(f, setting_name, setting_default, comment, current_tags)
      current_comment = []
      current_tags = []


def main(args):
  if '--check' in args:
    safe_ensure_dirs(path_from_root('out'))
    tmp_output = path_from_root('out/settings_reference.rst')
    with open(tmp_output, 'w') as f:
      write_file(f)
    if read_file(tmp_output) != read_file(output_file):
      print(f'{output_file} is out-of-date.  Please run tools/maint/update_settings_docs.py')
      subprocess.call(['diff', '-u', output_file, tmp_output])
      return 1
  else:
    with open(output_file, 'w') as f:
      write_file(f)

  return 0


if __name__ == '__main__':
  sys.exit(main(sys.argv[1:]))
